﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace AGDN
{
    class XnaArabicTextRender:IDisposable
    {
        private SpriteBatch spriteBatch;
        private Bitmap bitmap;
        private BitmapData bitmapData;
        private Graphics graphics;
        private StringFormat textFormat;
        private int stride;
        private int width;
        private int height;
        private bool mfixed = false;
        Texture2D texture;
        bool disposed = true;

        public XnaArabicTextRender(GraphicsDevice graphicsDevice)
        {
            spriteBatch = new SpriteBatch(graphicsDevice);
            textFormat = new StringFormat();
            DefaultTextFormat();
        }

        public XnaArabicTextRender(GraphicsDevice graphicsDevice, int width, int height)
            : this(graphicsDevice)
        {
            this.width = width;
            this.height = height;
            mfixed = true;
            BuildBitmap(width, height);
            texture = new Texture2D(spriteBatch.GraphicsDevice, width, height);
        }

        public XnaArabicTextRender(GraphicsDevice graphicsDevice, int width, int height, bool fixedResources)
            : this(graphicsDevice)
        {
            this.width = width;
            this.height = height;
            mfixed = fixedResources;
            if (mfixed)
            {
                BuildBitmap(width, height);
                texture = new Texture2D(spriteBatch.GraphicsDevice, width, height);
            }
        }

        public bool Fixed
        {
            get { return mfixed; }
            set { mfixed = value; }
        }

        public bool Disposed
        {
            get { return disposed; }
        }

        private void BuildBitmap(int width,int height)
        {
            Dispose();

            this.width = width;
            this.height = height;

            bitmap = new Bitmap(width, height, PixelFormat.Format32bppRgb);
            bitmapData = new BitmapData();
            graphics = Graphics.FromImage(bitmap);

            stride = (bitmap.Width * Bitmap.GetPixelFormatSize(PixelFormat.Format32bppRgb))/8;
            int iBytesCount = bitmap.Height * stride;

            unsafe
            {
                fixed (byte* nativeData = new byte[iBytesCount])
                {
                    bitmapData.Width = bitmap.Width;
                    bitmapData.Height = bitmap.Height;
                    bitmapData.PixelFormat = bitmap.PixelFormat;
                    bitmapData.Stride = stride;
                    bitmapData.Scan0 = (IntPtr)nativeData;
                }
            }
            
            disposed = false;
        }

        public void DrawString(string text, string font,float size,Microsoft.Xna.Framework.Graphics.Color color,Vector2 position)
        {
            Font theFont = new Font(font, size);

            if (!mfixed)
            {
                Size theSize = TextRenderer.MeasureText(text, theFont);

                if (theSize.Width > this.width || theSize.Height > this.height)
                {
                    BuildBitmap(theSize.Width, theSize.Height);

                    if (texture != null && !texture.IsDisposed)
                        texture.Dispose();

                    texture = new Texture2D(spriteBatch.GraphicsDevice, width, height);
                }
            }
            
            graphics.Clear(System.Drawing.Color.Transparent);
            System.Drawing.Color theColor = System.Drawing.Color.FromArgb(color.R,color.G,color.B);
            graphics.DrawString(text, theFont, new SolidBrush(theColor), new PointF(0f, 0f));
            System.Drawing.Rectangle rc = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height);
            bitmap.LockBits(rc, ImageLockMode.ReadOnly, bitmap.PixelFormat, bitmapData);
                int iBytesCount = bitmap.Height * bitmapData.Stride;
                byte[] data = new byte[iBytesCount];
                Marshal.Copy(bitmapData.Scan0, data, 0, iBytesCount);
            bitmap.UnlockBits(bitmapData);

            texture.GraphicsDevice.Textures[0] = null;
            texture.SetData<byte>(data);
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            spriteBatch.Draw(texture, position, Microsoft.Xna.Framework.Graphics.Color.White);
            spriteBatch.End();
        }

        public void Dispose()
        {
            if (!disposed)
            {
                bitmap.Dispose();
                graphics.Dispose();
                bitmap = null;
                graphics = null;
                bitmapData = null;
                texture.Dispose();
                texture = null;

                disposed = true;
            }
        }

        public StringFormat TextFormat
        {
            get { return textFormat; }
            set { textFormat = value; }
        }

        public void DefaultTextFormat()
        {
            textFormat.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.DirectionRightToLeft;
            textFormat.Alignment = StringAlignment.Near;
            textFormat.HotkeyPrefix = HotkeyPrefix.None;
            textFormat.LineAlignment = StringAlignment.Near;
            textFormat.Trimming = StringTrimming.None;
        }

        #region static members

        public static Microsoft.Xna.Framework.Point MeasureText(string text, string font, float size)
        {
            Font theFont = new Font(font, size);
            Size theSize = TextRenderer.MeasureText(text, theFont);
            return new Microsoft.Xna.Framework.Point(theSize.Width, theSize.Height);
        }

        #endregion
    }
}
